﻿/*
 * This code is part of the milkmidi Flash AS3 Library by milkmidi
 * http://milkmidi.com/
 * http://code.google.com/p/milkmidi/ 
 *
 * static mehod:
 *
 * play2    ( scopes: MovieClip , paramaters:Object = null ):void
 * playBack ( scopes: MovieClip , paramaters:Object = null ):void
 * go		( scopes: MovieClip , targetFrame:uint , paramaters:Object= null ):void
 * stopTween( scopes: MovieClip ) :void
 
 *
 *
 * Paramaters:
 *
 * frame			: int
 * speed			: int
 * delay 			: Number
 * onComplete		: Function
 * onCompleteParams	: Array 
 *
 * version:1.5
 * date: 2009/03/13
 * */
package milkmidi.utils
{	
	import flash.display.MovieClip;
	import flash.errors.IllegalOperationError;
	import flash.events.Event;	
	import flash.utils.Dictionary;	
	import flash.utils.setTimeout;
	import flash.utils.clearTimeout;
	
	/**
	 * 正播與倒播。
	 */
	public final class MyTween
	{
		private static const PLAY2		:String = "play2";
		private static const PLAYBACK	:String = "playBack";
		
		private static var _dictionaryMap:Dictionary = new Dictionary(true);		
		//  ____  ____  _    _  ____ _____ ____  _   _  ____ _____  ____  ____
		// / ___|/ _  \| \  | |/ ___|_   _|  _ \| | | |/ ___|_   _|/ _  \|  _ \
		//| |    || | ||  \ | |\___ \ | | | |_) | | | | |     | |  || | || |_)I
		//| |___ ||_| || | \| | ___) || | | _  /| |_| | |___  | |  ||_| || _  /
		// \____|\____/|_|\___||____/ |_| |_|\_\ \___/ \____| |_|  \____/|_|\_\
		//__________________________________________________________________________________ Constructor
		public function MyTween() { throw new IllegalOperationError("MyTween cannot be instantiated."); }		
		public static function echo():void {
			//Tracer.echo(_dictionaryMap , "MyTween._dictionaryMap");			
		}
		//  ____  _   _  _____  _    ___  ____
		// |  _ \| | | ||  _  \| |  |_ _|/ ___|
		// | |_) | | | || |_| /| |   | || |
		// |  __/| |_| || |_| \| |__ | || |___
		// |_|    \___/ |_____/|____|___|\____|
		//__________________________________________________________________________________ Public  Function
		/**
		 * 前往到指定的影格數。
		 * @param	pObj 目標物件。
		 * @param	pTargetFrame uint 目標影格數
		 * @param	pParameter default = null
		 */
		public static function go(pObj:Object, pTargetFrame:uint, pParameter:Object = null):void	{
			
			if ( checkDisplayObjectFasProperty(pObj) == false) 			
				throw new Error("Object must has prevFrame,nextFrame,currentFrame,totalFrames");	
				
			
			if (pObj["currentFrame"] == pTargetFrame) return;			
			
			if (pParameter == null)  pParameter = { frame:pTargetFrame };			
			else 					 pParameter.frame = pTargetFrame;
			
			if (pTargetFrame > pObj["currentFrame"] ) 
				MyTween._addTween(pObj , pParameter , MyTween.PLAY2);
			else 	
				MyTween._addTween(pObj , pParameter , MyTween.PLAYBACK);							
		}
		/**
		 * 正播影格
		 * @param	pObj 目標物件
		 * @param	pParameter default null 參數值。
		 */
		public static function play2    ( pObj:Object , pParameter:Object = null ):void {
			if ( checkDisplayObjectFasProperty(pObj) == false) 			
				throw new Error("Object must has prevFrame,nextFrame,currentFrame,totalFrames");						
				
			MyTween._addTween(pObj, pParameter, MyTween.PLAY2);
		}
		
		/**
		 * 倒播影格
		 * @param	pObj 目標物件
		 * @param	pParameter
		 */
		public static function playBack ( pObj:Object, pParameter:Object = null ):void {			
			if ( checkDisplayObjectFasProperty(pObj) == false) 				
				throw new Error("Object must has prevFrame,nextFrame,currentFrame,totalFrames");						
					
			MyTween._addTween(pObj, pParameter, MyTween.PLAYBACK);
		}
		/**
		 * 停止
		 * @param	pObj
		 */
		public static function stopTween(pObj:Object):void	{
			if ( checkDisplayObjectFasProperty(pObj) == false) {				
				throw new Error("Object must has prevFrame,nextFrame,currentFrame,totalFrames");						
			}					
			var _mc		:Object 		= pObj;			
			var _info	:MyTweenInfo 	= _dictionaryMap[_mc];
			if ( !_info)  return;					
			if (_info.inter != -1) clearTimeout(_info.inter);											
			
			_info.destroy();
			_dictionaryMap[pObj] = null;
			delete _dictionaryMap[pObj];						
		}
		//  ____  ____  _____     ___  _____ _____
		// |  _ \|  _ \|_ _\ \   / / \|_   _| ____|
		// | |_) | |_) || | \ \ / / _ \ | | |  _|
		// |  __/|  _ < | |  \ V / ___ \| | | |___
		// |_|   |_| \_\___|  \_/_/   \_\_| |_____|
        //__________________________________________________________________________________ Private Function
		
		private static function checkDisplayObjectFasProperty(pObj:Object):Boolean {
			if (pObj is MovieClip) return true;		
			return ("prevFrame" in pObj) && ("nextFrame" in pObj) && ("currentFrame" in pObj) && ("totalFrames" in pObj)			
		}		
		private static function _addTween(pObj:Object, pParameter:Object, pType:String):void {									
			
			if (_dictionaryMap[pObj])  stopTween(pObj);				
			
			var _info:MyTweenInfo = new MyTweenInfo(pObj, pParameter ,pType);				
			_dictionaryMap[pObj] = _info;
			
							
			if (pParameter != null && pParameter.delay) 			
				_info.inter = setTimeout(onTimeout, pParameter.delay * 1000, _info, pType);				
			else 
				MyTween.onTimeout(_info, pType);	
		}		
		private static function onTimeout(_info:MyTweenInfo, pType:String):void {			
			if (pType == MyTween.PLAY2)  _info.play2();
			else 				  		 _info.playBack();
		}		
		// _______     _______ _    _ _____
		//| ____\ \   / | ____| \  | |_   _|
		//|  _|  \ \ / /|  _| |  \ | | | |
		//| |___  \ V / | |___| | \| | | |
		//|_____|  \_/  |_____|_|\___| |_|
		//__________________________________________________________________________________ Event
	}
}


import flash.display.Sprite;
import flash.events.Event;
import milkmidi.utils.MyTween;
internal class MyTweenInfo {
	public var type				:String = "";
	public var inter			:int = -1;
	private var frame			:int = -1;	
	private var speed			:int = 1;
	private var onComplete		:Function = null
	private var onCompleteParams:Array = null;
	private var target			:Object;
	private var delay			:Number = 0;
	private var fps				:int = 30;	
	private var _sprite			:Sprite = new Sprite();
	public function MyTweenInfo(pObj:Object, pParameter:Object, pType:String) {			
		this.target = pObj;
		this.type = pType;		
		for (var a:String in pParameter) {
			this[a] = pParameter[a];
		}		
		if (this.frame == -1) this.frame = (pType ==  "play2") ? pObj.totalFrames : 1;		
	}	
	public function play2():void {
		removeAllListeners();		
		_sprite.addEventListener(Event.ENTER_FRAME , _onEventEnterPlay);
	}
	public function playBack():void {
		removeAllListeners()
		_sprite.addEventListener(Event.ENTER_FRAME , _onEventEnterBack);
	}
	private function removeAllListeners():void {
		_sprite.removeEventListener(Event.ENTER_FRAME , _onEventEnterPlay);
		_sprite.removeEventListener(Event.ENTER_FRAME , _onEventEnterBack);
	}
	private function _onEventEnterPlay(e:Event):void {							
		var i:int = speed;		
		//trace(target["currentFrame"] , frame);
		while (i--) {								
			if ( target["currentFrame"] == frame) {				
				onMyTweenComplete();
				break;
			} else{
				target.nextFrame();				
			}
		}
	}
	private function _onEventEnterBack(e:Event):void {			
		var i:int = speed;
		while (i--) {					
			if ( target["currentFrame"] == frame){
				onMyTweenComplete();			
				break;
			} else {				
				target.prevFrame();
			}
		}
	}
	private function onMyTweenComplete():void {
		if (onComplete != null) onComplete.apply(target, onCompleteParams);	
		MyTween.stopTween(target);		
	}
	public function destroy():void {
		removeAllListeners();
		_sprite = null;
		onComplete = null;
		onCompleteParams = null;
	}
	public function toString():String {
		return "[MyTweenInfo] type:" + this.type;
	}
}